/**
 * 
 */
package epsofts.Neutron.GUI;

import java.awt.BorderLayout;
import java.awt.Event;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import com.cloudgarden.layout.AnchorConstraint;
import com.cloudgarden.layout.AnchorLayout;

import epsofts.Neutron.Coup;
import epsofts.Neutron.EvalueurNbLibertes;
import epsofts.Neutron.EvalueurReseauNeurones;
import epsofts.Neutron.IEvalueur;
import epsofts.Neutron.IJoueur;
import epsofts.Neutron.INeutronUI;
import epsofts.Neutron.Jeu;
import epsofts.Neutron.JoueurHumain;
import epsofts.Neutron.JoueurMiniMaxAB;
import epsofts.Neutron.JoueurUCT;
import epsofts.Neutron.Plateau;
import epsofts.Neutron.eCase;
import epsofts.utils.EPFctPart;


/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
/**
 * @author Pierre ESCALLIER
 * 
 */
public class NeutronGUI implements INeutronUI
{
	static final private String	SCORES_FILENAME	= "scores";

	static final private int	MARGIN			= 90;

	static final private int	GAP				= 6;

	static final private String	IMG_PATH		= "resources" + File.separator + NeutronGUI.class.getPackage().getName().replace('.', File.separatorChar) + File.separator + "img" + File.separator;

	static final private class IJoueurPluginInfo
	{
		public String					label;

		public Boolean					enabled;

		public Class<? extends IJoueur>	clazz;
		
		public Class<? extends IEvalueur> clazzEvalueur;

		public IJoueurPluginInfo(String label, Boolean enabled, Class<? extends IJoueur> clazz, Class<? extends IEvalueur> clazzEvalueur)
		{
			this.label = label;
			this.enabled = enabled;
			this.clazz = clazz;
			this.clazzEvalueur = clazzEvalueur;
		}
	}

	final private Map<String, IJoueurPluginInfo>	m_classesJoueurs	= new HashMap<String, IJoueurPluginInfo>();

	static public NeutronGUI						application			= null;

	private Jeu										currentGame			= null;

	private IJoueurPluginInfo						currentPlayerBleu	= null;

	private IJoueurPluginInfo						currentPlayerRouge	= null;

	private JFrame									jFrame				= null;

	private JImagePanel								jContentPane		= null;

	private JMenuBar								jJMenuBar			= null;

	private JMenu									fileMenu			= null;

	private JMenu									helpMenu			= null;

	private JMenuItem								exitMenuItem		= null;

	private JMenuItem								aboutMenuItem		= null;

	private JMenuItem								newGameMenuItem		= null;

	private JDialog									aboutDialog			= null;									// @jve:decl-index=0:visual-constraint="379,25"

	private JPanel									aboutContentPane	= null;

	private JImagePanel[]							jImagePanels		= new JImagePanel[25];

	private int										victoiresRouges		= 0;

	private int										victoiresBleues		= 0;

	/**
	 * Coup courant � saisir. coup[0] : NeutronDest, coup[1] : BilleOrigine, coup[2] : BilleDest.
	 */
	public Vector<Integer>							m_coup				= new Vector<Integer>(3);					// @jve:decl-index=0:

	public enum eEtat
	{
		WAIT, SEL_NEUTRON_DEST, SEL_BILLE, SEL_BILLE_DEST
	};

	public eEtat		m_Etat		= eEtat.WAIT;		// @jve:decl-index=0:
	private JMenuItem optionsRAZScoresMenu;

	private JEditorPane	jEditorPane1;

	private JMenuItem	coupSuivantMenuItem;

	private JMenuItem	coupPrecedentMenuItem;

	private JMenu		optionsRougeMenu;

	private JMenu		optionsBleuMenu;

	private JMenu		optionMenu;

	/**
	 * Plateau courant.
	 */
	private Plateau		m_plateau	= new Plateau();	// @jve:decl-index=0:

	/**
	 * This method initializes jImagePanels
	 * 
	 * @return javax.swing.JPanel
	 */
	JImagePanel getJImagePanels(int rang)
	{
		if (jImagePanels[rang] == null)
		{
			jImagePanels[rang] = new JImagePanel();
			jImagePanels[rang].setOpaque(false);
			jImagePanels[rang].setRang(rang);
			jImagePanels[rang].setKeepAspect(false);
			jImagePanels[rang].setAutoSize(true);

			jImagePanels[rang].setLayout(new GridBagLayout());
		}
		return jImagePanels[rang];
	}

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		// TODO Auto-generated method stub
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				try
				{
					NeutronGUI.application = new NeutronGUI();
				}
				catch (IOException e)
				{
					e.printStackTrace();
					return;
				}
				NeutronGUI.application.getJFrame().setVisible(true);
			}
		});
	}

	/**
	 * @throws IOException
	 * 
	 */
	public NeutronGUI() throws IOException
	{
		List<Class<? extends IJoueur>> listeClassesJoueurs = EPFctPart.GetImplementationsClasses(IJoueur.class.getPackage().getName().replace('.', '/'), IJoueur.class);
		List<Class<? extends IEvalueur>> listeClassesEvalueur = EPFctPart.GetImplementationsClasses(IEvalueur.class.getPackage().getName().replace('.', '/'), IEvalueur.class);

		for (Class<? extends IJoueur> c : listeClassesJoueurs)
		{
			String label;
			Boolean enabled;
			
			try
			{
				Field labelField = c.getField("LABEL");
				label = labelField.get(null).toString();
			}
			catch (Exception e)
			{
				label = c.getName();
			}

			try
			{
				Field enabledField = c.getField("ENABLED");
				enabled = Boolean.valueOf(enabledField.get(null).toString());
			}
			catch (Exception e)
			{
				enabled = false;
			}

			boolean useEvalueur = false;
			for(Constructor<?> ctor : c.getConstructors())
			{
				for(Class<?> ptype : ctor.getParameterTypes())
				{
					if (IEvalueur.class.isAssignableFrom(ptype))
					{
						useEvalueur = true;
						break;
					}
				}
				if (useEvalueur) break;
			}						
			
			if (useEvalueur)
			{
				for(Class<? extends IEvalueur> e : listeClassesEvalueur)
				{
					String evalLabel=null;
					try
					{
						Field labelField = e.getField("LABEL");
						evalLabel = labelField.get(null).toString();
					}
					catch (Exception ex)
					{
						evalLabel = e.getName();
					}
					
					evalLabel = label+" "+evalLabel;
					m_classesJoueurs.put(evalLabel, new IJoueurPluginInfo(evalLabel, enabled, c, e));
				}
			}
			else
			{
				m_classesJoueurs.put(label, new IJoueurPluginInfo(label, enabled, c, null));
			}
		}

		m_coup.removeAllElements();
		m_coup.add(null);
		m_coup.add(null);
		m_coup.add(null);

		loadScores();
	}

	private void loadScores()
	{
		ObjectInputStream ois = null;
		try
		{
			try
			{
				ois = new ObjectInputStream(new FileInputStream(SCORES_FILENAME));
				victoiresBleues = ois.readInt();
				victoiresRouges = ois.readInt();
			}
			catch (FileNotFoundException e)
			{
				File scoreFile = new File(SCORES_FILENAME);
				scoreFile.createNewFile();
			}
		}
		catch (EOFException e)
		{
			// Nothing
		}
		catch (IOException e)
		{
			JOptionPane.showMessageDialog(null, "Erreur I/O avec le fichier des scores \"" + SCORES_FILENAME + "\"\n"+e.getLocalizedMessage(), "Erreur I/O", JOptionPane.ERROR_MESSAGE);
			e.printStackTrace();
		}
		finally
		{
			if (ois != null)
			{
				try
				{
					ois.close();
				}
				catch (IOException e)
				{
					// Nothing
				}
			}
		}
	}

	private void saveScores()
	{
		ObjectOutputStream oos = null;
		try
		{
			oos = new ObjectOutputStream(new FileOutputStream(SCORES_FILENAME));
			oos.writeInt(victoiresBleues);
			oos.writeInt(victoiresRouges);
		}
		catch (IOException e)
		{
			JOptionPane.showMessageDialog(null, "Erreur I/O avec le fichier des scores \"" + SCORES_FILENAME + "\"\n"+e.getLocalizedMessage(), "Erreur I/O", JOptionPane.ERROR_MESSAGE);
		}
		finally
		{
			try
			{
				oos.close();
			}
			catch (IOException e)
			{
				// Nothing
			}
		}
	}
	
	/**
	 * This method initializes jFrame
	 * 
	 * @return javax.swing.JFrame
	 */
	private JFrame getJFrame()
	{
		if (jFrame == null)
		{
			jFrame = new JFrame();
			jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			jFrame.setBounds(0, 0, 300, 300);
			jFrame.setJMenuBar(getJJMenuBar());
			jFrame.setContentPane(getJContentPane());
			jFrame.setTitle("JNeutron");
		}
		return jFrame;
	}

	/**
	 * This method initializes jContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJContentPane()
	{
		if (jContentPane == null)
		{
			jContentPane = new JImagePanel();
			jContentPane.setImage(IMG_PATH + "planche.png");
			jContentPane.setAutoSize(true);
			jContentPane.setKeepAspect(false);
			jContentPane.setBackground(new java.awt.Color(0, 0, 255));
			AnchorLayout borderLayout = new AnchorLayout();
			jContentPane.setLayout(borderLayout);
			jContentPane.setPreferredSize(new java.awt.Dimension(290, 260));
			jContentPane.setLocation(new java.awt.Point(0, 0));
			jContentPane.setOpaque(false);
			jContentPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));

			JPanel jMarginPanel = new JPanel();
			BorderLayout jPanel1Layout = new BorderLayout();
			jMarginPanel.setLayout(jPanel1Layout);
			{
				JPanel insidePane = new JPanel();
				jMarginPanel.add(insidePane, BorderLayout.CENTER);
				insidePane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
				// insidePane.setBackground(Color.BLUE);
				GridLayout gridLayout = new GridLayout(5, 5);
				gridLayout.setColumns(5);
				gridLayout.setRows(5);
				gridLayout.setHgap(GAP);
				gridLayout.setVgap(GAP);
				insidePane.setLayout(gridLayout);
				insidePane.setBackground(new java.awt.Color(255, 0, 0));
				insidePane.setOpaque(false);

				for (int i = 0; i < 25; ++i)
				{
					insidePane.add(getJImagePanels(i), null);
				}

				jContentPane.add(jMarginPanel, new AnchorConstraint(MARGIN, 1000 - MARGIN, 1000 - MARGIN, MARGIN, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL, AnchorConstraint.ANCHOR_REL));
				jMarginPanel.setBackground(new java.awt.Color(255, 255, 255));
				jMarginPanel.setPreferredSize(new java.awt.Dimension(290, 260));
				jMarginPanel.setOpaque(false);
				jMarginPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
			}
		}

		return jContentPane;
	}

	/**
	 * This method initializes jJMenuBar
	 * 
	 * @return javax.swing.JMenuBar
	 */
	private JMenuBar getJJMenuBar()
	{
		if (jJMenuBar == null)
		{
			jJMenuBar = new JMenuBar();
			jJMenuBar.add(getFileMenu());
			jJMenuBar.add(getOptionMenu());
			jJMenuBar.add(getHelpMenu());
		}
		return jJMenuBar;
	}

	/**
	 * This method initializes jMenu
	 * 
	 * @return javax.swing.JMenu
	 */
	private JMenu getFileMenu()
	{
		if (fileMenu == null)
		{
			fileMenu = new JMenu();
			fileMenu.setText("Partie");
			fileMenu.add(getNewGameMenuItem());
			fileMenu.add(getCoupPrecedentMenuItem());
			fileMenu.add(getCoupSuivantMenuItem());
			fileMenu.add(getExitMenuItem());
		}
		return fileMenu;
	}

	/**
	 * This method initializes jMenu
	 * 
	 * @return javax.swing.JMenu
	 */
	private JMenu getHelpMenu()
	{
		if (helpMenu == null)
		{
			helpMenu = new JMenu();
			helpMenu.setText("?");
			helpMenu.add(getAboutMenuItem());
		}
		return helpMenu;
	}

	/**
	 * This method initializes jMenuItem
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenuItem getExitMenuItem()
	{
		if (exitMenuItem == null)
		{
			exitMenuItem = new JMenuItem();
			exitMenuItem.setText("Quitter");
			exitMenuItem.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					System.exit(0);
				}
			});
		}
		return exitMenuItem;
	}

	/**
	 * This method initializes jMenuItem
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenuItem getAboutMenuItem()
	{
		if (aboutMenuItem == null)
		{
			aboutMenuItem = new JMenuItem();
			aboutMenuItem.setText("A propos du jeu du Neutron");
			aboutMenuItem.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent e)
				{
					JDialog aboutDialog = getAboutDialog();
					aboutDialog.pack();
					Point loc = getJFrame().getLocation();
					loc.translate(20, 20);
					aboutDialog.setLocation(loc);
					aboutDialog.setVisible(true);
				}
			});
		}
		return aboutMenuItem;
	}

	/**
	 * This method initializes aboutDialog
	 * 
	 * @return javax.swing.JDialog
	 */
	private JDialog getAboutDialog()
	{
		if (aboutDialog == null)
		{
			aboutDialog = new JDialog(getJFrame(), true);
			aboutDialog.setTitle("A propos");
			aboutDialog.setPreferredSize(new java.awt.Dimension(600, 300));
			aboutDialog.setSize(600, 300);
			aboutDialog.setContentPane(getAboutContentPane());
		}
		return aboutDialog;
	}

	/**
	 * This method initializes aboutContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getAboutContentPane()
	{
		if (aboutContentPane == null)
		{
			aboutContentPane = new JPanel();
			aboutContentPane.setLayout(new BorderLayout());
			aboutContentPane.setPreferredSize(new java.awt.Dimension(600, 300));
			aboutContentPane.add(getJEditorPane1(), BorderLayout.CENTER);
		}
		return aboutContentPane;
	}

	/**
	 * This method initializes jMenuItem
	 * 
	 * @return javax.swing.JMenuItem
	 */
	private JMenuItem getNewGameMenuItem()
	{
		if (newGameMenuItem == null)
		{
			newGameMenuItem = new JMenuItem();
			newGameMenuItem.setText("Nouveau jeu");
			newGameMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK, true));
			newGameMenuItem.addActionListener(new java.awt.event.ActionListener()
			{
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					if ((currentGame != null) && ( !currentGame.estTermine()))
					{
						if (JOptionPane.showConfirmDialog(null, "La partie en cours n'est pas terminée, continuer ?", "Attention", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION)
						{
							return;
						}

						currentGame.Stopper();
					}

					/*
					 * JDialog newGameDialog = getJNewGameDialog(); newGameDialog.pack(); Point loc = getJFrame().getLocation(); loc.translate(20, 20); newGameDialog.setLocation(loc); m_NewGameReturn = false; newGameDialog.setModal(true); newGameDialog.setVisible(true);
					 */

					new Runnable()
					{
						public void run()
						{
							try
							{
								IJoueur rouge = joueurFactory(currentPlayerRouge.clazz, currentPlayerRouge.clazzEvalueur);
								IJoueur bleu = joueurFactory(currentPlayerBleu.clazz, currentPlayerBleu.clazzEvalueur);

								if (currentGame == null)
								{
									currentGame = new Jeu(application, rouge, bleu);
								}
								else
								{
									refreshJoueurs();
								}
							}
							catch (ClassNotFoundException e)
							{
								e.printStackTrace();
								return;
							}
							currentGame.Redemarrer();

							// System.out.println("actionPerformed()"); // TODO Auto-generated Event stub actionPerformed()
						}
					}.run();
				}
			});
		}
		return newGameMenuItem;
	}

	private final Map<String, IJoueur>	m_joueursCache	= new HashMap<String, IJoueur>();

	private IJoueur joueurFactory(final Class<? extends IJoueur> i_classe, final Class<? extends IEvalueur> i_classeEvalueur) throws ClassNotFoundException
	{
		// TODO : Remplacer par qqchose de g�n�rique (chaque classe fille int�gre et affiche sa boite de dialogue de param�tres).

		if (m_joueursCache.containsKey(i_classe.getCanonicalName()))
		{
			return m_joueursCache.get(i_classe.getCanonicalName());
		}

		IJoueur result = null;
		IEvalueur evalueur = null;
		
		if (i_classeEvalueur == EvalueurNbLibertes.class)
		{
			evalueur = new EvalueurNbLibertes();
		}
		if (i_classeEvalueur == EvalueurReseauNeurones.class)
		{
			evalueur = new EvalueurReseauNeurones();
		}

		if (i_classe == JoueurHumain.class)
		{
			result = new JoueurHumain();
		}
		if (i_classe == JoueurMiniMaxAB.class)
		{
			result = new JoueurMiniMaxAB((short) 4, evalueur, (short) 2);
		}
		if (i_classe == JoueurUCT.class)
		{
			result = new JoueurUCT(30000, evalueur, (short) 0); 
		}
		if (i_classe == epsofts.Neutron.GUI.JoueurHumainGUI.class)
		{
			result = JoueurHumainGUI.createInstance(application);
		}

		if (result == null) throw new ClassNotFoundException("Classe charg�e, mais construction inconnue.");

		m_joueursCache.put(i_classe.getCanonicalName(), result);
		return result;
	}

	public synchronized void setPlateau(Plateau i_plateau)
	{
		m_plateau = i_plateau;

		eCase cases[] = m_plateau.getCases();
		eCase tour = m_plateau.getTour();
		m_Etat = eEtat.WAIT;

		String sFichier = null;

		for (short i = 0; i < 25; ++i)
		{
			// On d�finie les images cliquables
			if (cases[i] == tour)
			{
				getJImagePanels(i).set_etat(eEtat.SEL_BILLE);
			}
			else
			{
				getJImagePanels(i).set_etat(eEtat.WAIT);
			}

			if (cases[i] == eCase.VIDE)
			{
				sFichier = null;
			}
			else
			{
				sFichier = IMG_PATH + getImgFile(cases[i]) + ".png";
			}

			getJImagePanels(i).setImage(sFichier);
		}

		Coup dernierCoup = m_plateau.getDernierCoup();
		if (dernierCoup != null)
		{
			getJImagePanels(dernierCoup.getBilleDestination()).setImage(IMG_PATH + getImgFile(cases[dernierCoup.getBilleDestination()]) + "_s.png");

			if (cases[dernierCoup.getBilleOrigine()] == eCase.VIDE)
			{
				getJImagePanels(dernierCoup.getBilleOrigine()).setImage(IMG_PATH + "move.png");
			}

			if (cases[dernierCoup.getNeutronOrigine()] == eCase.VIDE)
			{
				getJImagePanels(dernierCoup.getNeutronOrigine()).setImage(IMG_PATH + "moven.png");
			}
		}

		jFrame.setTitle("JNeutron - " + getTableauVictoires() + "   " + String.format("Au joueur %s de jouer", (tour == eCase.BLEUE) ? "Bleu" : (tour == eCase.ROUGE) ? "Rouge" : "??"));
		jFrame.repaint();
	}

	private String getTableauVictoires()
	{
		return String.format("Bleu: %d; Rouge: %d", victoiresBleues, victoiresRouges);
	}

	private static String getImgFile(eCase bille)
	{
		switch (bille)
		{
		case VIDE:
		{
			return null;
		}
		case BLEUE:
		{
			return "bleu";
		}
		case ROUGE:
		{
			return "rouge";
		}
		case NEUTRON:
		{
			return "neutron";
		}
		default:
			return null;
		}
	}

	public synchronized int saisieNeutronDestination() throws InterruptedException
	{
		short iNeutron = m_plateau.getNeutron();

		// On met en surbrillance le neutron
		getJImagePanels(iNeutron).setImage(IMG_PATH + "neutron_s.png");

		short coups[] = m_plateau.listerCoupsBille(iNeutron);

		// On met en "jaune" les coups possibles pour le neutron.
		for (short i = 0; i < 8; ++i)
		{
			if (coups[i] != iNeutron)
			{
				getJImagePanels(coups[i]).setImage(IMG_PATH + "jaune.png");
				getJImagePanels(coups[i]).set_etat(eEtat.SEL_NEUTRON_DEST);
			}
		}

		jFrame.repaint();

		synchronized (m_coup)
		{
			m_Etat = eEtat.SEL_NEUTRON_DEST;
			m_coup.set(0, null);
			while (m_coup.get(0) == null)
			{
				// On attend qu'une case soit cliqu�e.
				m_coup.wait();
			}

			// On efface les "coups possibles" jaunes.
			for (short i = 0; i < 8; ++i)
			{
				if (coups[i] != iNeutron)
				{
					getJImagePanels(coups[i]).setImage((String) null);
					getJImagePanels(coups[i]).set_etat(eEtat.WAIT);
				}
			}

			// On d�place le neutron
			getJImagePanels(iNeutron).setImage((String) null);
			getJImagePanels(m_coup.get(0)).setImage(IMG_PATH + "neutron.png");

			jFrame.repaint();

			return m_coup.get(0);
		}
	}

	public synchronized Vector<Integer> saisieBilleOrigineDestination() throws InterruptedException
	{
		eCase tour = m_plateau.getTour();
		// On attend que le joueur s�lectionne une bille
		synchronized (m_coup)
		{
			m_Etat = eEtat.SEL_BILLE;
			m_coup.set(1, null);
			while (m_coup.get(1) == null)
			{
				// On attend qu'une case soit cliqu�e.
				m_coup.wait();
			}
		}

		int iBilleOrigine = m_coup.get(1);

		String sCouleur = "";
		switch (tour)
		{
		case ROUGE:
		{
			sCouleur = "rouge";
			break;
		}
		case BLEUE:
		{
			sCouleur = "bleu";
			break;
		}
		}

		do
		{
			// On met la bille en surbrillance
			getJImagePanels(m_coup.get(1)).setImage(IMG_PATH + sCouleur + "_s.png");

			short coups[] = m_plateau.listerCoupsBille(m_coup.get(1).shortValue(), m_coup.get(0).shortValue());

			// On met en "jaune" les coups possibles pour la bille choisie.
			for (short i = 0; i < 8; ++i)
			{
				if (coups[i] != m_coup.get(1))
				{
					getJImagePanels(coups[i]).setImage(IMG_PATH + "jaune.png");
					getJImagePanels(coups[i]).set_etat(eEtat.SEL_BILLE_DEST);
				}
			}

			jFrame.repaint();

			synchronized (m_coup)
			{
				iBilleOrigine = m_coup.get(1);
				m_Etat = eEtat.SEL_BILLE_DEST;
				m_coup.set(2, null);
				while ((m_coup.get(2) == null) && (m_Etat == eEtat.SEL_BILLE_DEST))
				{
					// On attend qu'une case soit cliqu�e.
					m_coup.wait();
				}

				// On efface les "coups possibles" jaunes.
				for (short i = 0; i < 8; ++i)
				{
					if (coups[i] != iBilleOrigine)
					{
						getJImagePanels(coups[i]).setImage((String) null);
						getJImagePanels(coups[i]).set_etat(eEtat.WAIT);
					}
				}

				// On efface la surbrillance.
				getJImagePanels(iBilleOrigine).setImage(IMG_PATH + sCouleur + ".png");
			}

		} while (m_Etat == eEtat.SEL_BILLE);

		// On d�place la bille.
		getJImagePanels(m_coup.get(1)).setImage((String) null);
		getJImagePanels(m_coup.get(2)).setImage(IMG_PATH + sCouleur + ".png");

		jFrame.repaint();

		Vector<Integer> vRetour = new Vector<Integer>();
		vRetour.removeAllElements();
		vRetour.add(m_coup.get(1));
		vRetour.add(m_coup.get(2));
		return vRetour;
	}

	/**
	 * @return the etat
	 */
	public eEtat getEtat()
	{
		return m_Etat;
	}

	private JMenu getOptionMenu()
	{
		if (optionMenu == null)
		{
			optionMenu = new JMenu();
			optionMenu.setText("Options");
			optionMenu.add(getOptionsBleuMenu());
			optionMenu.add(getOptionsRougeMenu());
			optionMenu.add(getOptionsRAZScoresMenu());
		}
		return optionMenu;
	}

	private JMenu getOptionsBleuMenu()
	{
		if (optionsBleuMenu == null)
		{
			optionsBleuMenu = new JMenu();
			optionsBleuMenu.setText("Bleu");
			fillJoueurMenu(optionsBleuMenu, eCase.BLEUE);
			((JRadioButtonMenuItem) optionsBleuMenu.getPopupMenu().getComponent(0)).doClick();
		}
		return optionsBleuMenu;
	}

	private JMenu getOptionsRougeMenu()
	{
		if (optionsRougeMenu == null)
		{
			optionsRougeMenu = new JMenu();
			optionsRougeMenu.setText("Rouge");
			fillJoueurMenu(optionsRougeMenu, eCase.ROUGE);
			((JRadioButtonMenuItem) optionsRougeMenu.getPopupMenu().getComponent(0)).doClick();
		}
		return optionsRougeMenu;
	}

	private void fillJoueurMenu(final JMenu menu, final eCase joueur)
	{
		ButtonGroup buttonGroup = new ButtonGroup();

		Iterator<String> it = m_classesJoueurs.keySet().iterator();
		while (it.hasNext())
		{
			IJoueurPluginInfo plugin = m_classesJoueurs.get(it.next());
			if (plugin.enabled)
			{
				final JRadioButtonMenuItem radio = new JRadioButtonMenuItem(plugin.label);
				radio.addActionListener(new ActionListener()
				{

					@Override
					public void actionPerformed(ActionEvent e)
					{
						// TODO Changer l'IA du joueur en cours.
						System.out.println("Joueur " + menu.getText() + " => " + radio.getText());
						if (joueur == eCase.BLEUE)
						{
							currentPlayerBleu = m_classesJoueurs.get(radio.getText());
						}
						else if (joueur == eCase.ROUGE)
						{
							currentPlayerRouge = m_classesJoueurs.get(radio.getText());
						}

						refreshJoueurs();
					}
				});

				menu.add(radio);
				buttonGroup.add(radio);
			}
			else
			{
				System.out.println("IJoueur plugin \"" + plugin.label + "\" is disabled.");
			}
		}
	}

	private void refreshJoueurs()
	{
		if (currentGame == null) return;

		try
		{
			currentGame.setJoueurBleu(joueurFactory(currentPlayerBleu.clazz, currentPlayerBleu.clazzEvalueur));
		}
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}

		try
		{
			currentGame.setJoueurRouge(joueurFactory(currentPlayerRouge.clazz, currentPlayerRouge.clazzEvalueur));
		}
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
	}

	private JMenuItem getCoupPrecedentMenuItem()
	{
		if (coupPrecedentMenuItem == null)
		{
			coupPrecedentMenuItem = new JMenuItem();
			coupPrecedentMenuItem.setText("Coup précédent");
			coupPrecedentMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.CTRL_MASK, true));
			coupPrecedentMenuItem.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent evt)
				{
					if (currentGame == null) return;

					refreshJoueurs();
					currentGame.Precedent();
				}
			});
		}
		return coupPrecedentMenuItem;
	}

	private JMenuItem getCoupSuivantMenuItem()
	{
		if (coupSuivantMenuItem == null)
		{
			coupSuivantMenuItem = new JMenuItem();
			coupSuivantMenuItem.setText("Coup suivant");
			coupSuivantMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.CTRL_MASK | Event.SHIFT_MASK, true));
			coupSuivantMenuItem.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent evt)
				{
					if (currentGame == null) return;

					refreshJoueurs();
					currentGame.Suivant();
				}
			});
		}
		return coupSuivantMenuItem;
	}

	private JEditorPane getJEditorPane1()
	{
		if (jEditorPane1 == null)
		{
			jEditorPane1 = new JEditorPane();
			jEditorPane1.setContentType("text/html");
			jEditorPane1.setText("<h1><center>JNeutron v1.0</center></h1>Règles :<br>Le joueur doit obligatoirement déplacer le neutron puis un de ses pions.<br>Les pions se déplacent en diagonales ou sur les verticales sans s'arrêter jusqu'à ce qu'ils rencontrent un obstacle (le bord du damier ou un autre pion).<br>Le joueur qui commence la partie ne déplace pas le neutron au premier tour.<br>Le joueur qui amène le neutron dans son camp a gagné.<br>Si un joueur ne peut pas déplacer le neutron ou l'un de ses pions il a perdu, de même s'il est obligé d'amener le neutron dans le camp adverse.<br><p align='center'><a href='http://jneutron.axan.org/'>http://jneutron.axan.org/</a><br><a href='mailto:axan@axan.org'>axan@axan.org</a></p>");
			jEditorPane1.setEditable(false);
			jEditorPane1.setPreferredSize(new java.awt.Dimension(600, 300));
			jEditorPane1.setFocusable(false);
		}
		return jEditorPane1;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see epsofts.Neutron.INeutronUI#OnJeuFini(epsofts.Neutron.eCase)
	 */
	@Override
	public void OnJeuFini(eCase vainqueur)
	{
		if (vainqueur == eCase.ROUGE)
		{
			++victoiresRouges;
		}
		else if (vainqueur == eCase.BLEUE)
		{
			++victoiresBleues;
		}

		jFrame.setTitle("JNeutron - " + getTableauVictoires() + "   " + String.format("Le joueur %s a gagné", (vainqueur == eCase.BLEUE) ? "Bleu" : (vainqueur == eCase.ROUGE) ? "Rouge" : "??"));

		jFrame.repaint();
		
		saveScores();
	}
	
	private JMenuItem getOptionsRAZScoresMenu() {
		if(optionsRAZScoresMenu == null) {
			optionsRAZScoresMenu = new JMenuItem();
			optionsRAZScoresMenu.setText("Effacer scores");
			optionsRAZScoresMenu.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent evt) {
					victoiresBleues = 0;
					victoiresRouges = 0;
					saveScores();
					
					getJFrame().setTitle("JNeutron");
				}
			});
		}
		return optionsRAZScoresMenu;
	}

}
